package views;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.MaskFormatter;

import models.ListItem;
import models.ListTransferHandler;
import models.ModelListImport;
import models.ModelMyPlayer;

import org.ini4j.Ini;
import org.ini4j.InvalidFileFormatException;

import uk.co.caprica.vlcj.filter.VideoFileFilter;
import uk.co.caprica.vlcj.medialist.MediaList;
import uk.co.caprica.vlcj.player.MediaPlayer;
import uk.co.caprica.vlcj.player.MediaPlayerEventAdapter;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.player.list.MediaListPlayer;
import variables.VarConfigInt;
import variables.VarErreurInt;
import variables.VarLangInt;
import variables.VarSystemInt;
import controllers.ActionAboutListener;
import controllers.ActionCloseListener;
import controllers.ActionConcatVideoListener;
import controllers.ActionCutListener;
import controllers.ActionNotYetListener;
import controllers.ActionOpenListener;
import controllers.ActionPlayerButtonListener;

public class FenetrePrincipale extends JPanel implements Observer,
		ComponentListener {
	protected static final long serialVersionUID = 7354350768234256061L;

	protected JFrame fenetrePrincipale;
	protected Ini configIni;
	protected Ini langIni;
	protected ModelMyPlayer myPlayer;
	protected ModelListImport myListImport;

	// Taille de l'écran
	protected Dimension screenSize = java.awt.Toolkit.getDefaultToolkit()
			.getScreenSize();

	// Barre de menu
	protected final JMenuBar myMenuBar = new JMenuBar();

	// Initialisation du lecteur
	protected Canvas canvas;
	protected EmbeddedMediaPlayer mediaPlayer;
	protected MediaPlayerFactory mediaPlayerFactory;
	protected MediaList mediaList;
	protected MediaListPlayer mediaListPlayer;
	protected VideoFileFilter filter;

	// Barre de video
	protected JSlider timeBar = new JSlider(0, 100);
	protected JSlider volumeSlider = new JSlider(0, 200);

	// Panels
	protected JSplitPane splitPaneLeft;
	protected JSplitPane splitPaneRight;
	protected JPanel canvasPanel;
	protected JLabel currentTime, endTime;

	// editPanel
	protected JPanel editPanel;
	protected JLabel startCutLabel;
	protected JLabel endCutLabel;

	protected JTextField startTF;
	protected JTextField durationTF;
	protected JButton cutButton;

	// import
	@SuppressWarnings("rawtypes")
	protected DefaultListModel listImportModel = new DefaultListModel();
	// creation de la liste drable
	@SuppressWarnings("rawtypes")
	protected JList listImport = new JList();

	public FenetrePrincipale(Ini ini) {
		// Resize listener
		this.addComponentListener(this);

		// MVC
		this.myPlayer = new ModelMyPlayer();
		this.myListImport = new ModelListImport();
		this.myPlayer.addObserver(this);
		this.myListImport.addObserver(this);

		// Lecture du .ini de config
		this.configIni = ini;
		// Lecture di .ini pour la langue
		Ini.Section systemLang = configIni
				.get(VarConfigInt.CONFIG_SECTION_LOCALE);
		// Recuperation du fichier .ini
		try {
			this.langIni = new Ini(new File(VarLangInt.LANG_INI_REP
					+ systemLang.get(VarConfigInt.CONFIG_VAR_LOCALE_LANG)
					+ VarLangInt.LANG_INI_EXT));
		} catch (InvalidFileFormatException e) {
			new FenetreNewError(VarErreurInt.ERREUR_CONFIG_INVALIDE_FORMAT);
		} catch (IOException e) {
			new FenetreNewError(VarErreurInt.ERREUR_CONFIG_INVALIDE_TYPE);
		}

		// Création du lecteur
		this.canvas = new Canvas();
		this.canvas.setSize(new Dimension((int) (screenSize.getWidth() * 0.5),
				(int) (screenSize.getHeight() * 0.5)));
		this.canvas.setBackground(Color.black);

		try {
			mediaPlayerFactory = new MediaPlayerFactory("--no-video-title-show");
			mediaPlayer = mediaPlayerFactory.newEmbeddedMediaPlayer();
			mediaPlayer.setVideoSurface(mediaPlayerFactory
					.newVideoSurface(this.canvas));

			// Important: associate the media player with the media list player
			mediaListPlayer = mediaPlayerFactory.newMediaListPlayer();
			mediaListPlayer.setMediaPlayer(mediaPlayer);
			this.mediaList = mediaPlayerFactory.newMediaList();
		} catch (Exception e) {
			e.printStackTrace();
			new FenetreNewError(VarErreurInt.ERREUR_VLC_PLUGING);
		}
		
		// Ajout de la barre de menu
		this.createJMenuBar();

		// Creation du JPanel
		this.initPanel();

		// Creation de la frame
		this.createJFrame();
	}

	/**
	 * Creation de la fenetre principale
	 * 
	 * @param nomFenetre
	 */
	public void createJFrame() {
		// Récupération de la taille pour la fenêtre
		Ini.Section size = configIni.get(VarConfigInt.CONFIG_SECTION_SIZE);

		// Création de la frame
		this.fenetrePrincipale = new JFrame(VarConfigInt.CONFIG_SOFTWARE_NAME
				+ " " + VarConfigInt.CONFIG_SOFTWARE_VERSION);
		this.fenetrePrincipale
				.setMinimumSize(new Dimension(Integer.parseInt(size
						.get(VarConfigInt.CONFIG_VAR_SIZE_WIDTH)),
						Integer.parseInt(size
								.get(VarConfigInt.CONFIG_VAR_SIZE_HEIGHT))));
		this.fenetrePrincipale.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.fenetrePrincipale.setSize(this.fenetrePrincipale.getToolkit()
				.getScreenSize());
//		this.fenetrePrincipale.setSize(800,600);
		this.fenetrePrincipale.setJMenuBar(this.myMenuBar);
		this.fenetrePrincipale.setContentPane(this);
		this.fenetrePrincipale.setLocationRelativeTo(null);
		this.fenetrePrincipale.setVisible(true);
		this.refresh(this.fenetrePrincipale);
	}

	/**
	 * refresh le component passé en paramètre
	 * 
	 * @param component
	 */
	public void refresh(Component component) {
		component.invalidate();
		component.validate();
		component.repaint();
	}

	/**
	 * Creation de la barre de menu
	 */
	public void createJMenuBar() {
		// Récupération du nom des champs
		Ini.Section lang = langIni.get(VarLangInt.LANG_SECTION_MENU);

		// Menus
		JMenu filesMenu = new JMenu(lang.get(VarLangInt.LANG_VAR_MENU_FILES));
		JMenu toolsMenu = new JMenu(lang.get(VarLangInt.LANG_VAR_MENU_TOOLS));
		JMenu helpMenu = new JMenu(lang.get(VarLangInt.LANG_VAR_MENU_HELP));

		// Sous-Menus
		JMenuItem openMenuItem = new JMenuItem(
				lang.get(VarLangInt.LANG_VAR_MENU_OPEN));
		JMenuItem saveAsMenuItem = new JMenuItem(
				lang.get(VarLangInt.LANG_VAR_MENU_SAVEAS));
		JMenuItem closeMenuItem = new JMenuItem(
				lang.get(VarLangInt.LANG_VAR_MENU_CLOSE));
		JMenuItem configMenuItem = new JMenuItem(
				lang.get(VarLangInt.LANG_VAR_MENU_CONFIG));
		JMenuItem softMenuItem = new JMenuItem(
				lang.get(VarLangInt.LANG_VAR_MENU_SOFTW));

		System.out.println(lang.get(VarLangInt.LANG_VAR_MENU_SOFTW));
		// Ajout des actionListeners dans les sous-menus
		// TODO faire les actionListeners pour les menus
		openMenuItem.addActionListener(new ActionOpenListener(
				this.fenetrePrincipale, this.mediaPlayer, this.myPlayer,
				this.myListImport, this.volumeSlider, this.configIni));
		saveAsMenuItem.addActionListener(new ActionNotYetListener());
		closeMenuItem.addActionListener(new ActionCloseListener());
		configMenuItem.addActionListener(new ActionNotYetListener());
		softMenuItem.addActionListener(new ActionAboutListener());

		// Ajout des sous-menu dans les menus
		filesMenu.add(openMenuItem);
		filesMenu.add(saveAsMenuItem);
		filesMenu.add(closeMenuItem);
		toolsMenu.add(configMenuItem);
		helpMenu.add(softMenuItem);

		// Ajout des Menus dans la barre
		this.myMenuBar.add(filesMenu);
		this.myMenuBar.add(toolsMenu);
		this.myMenuBar.add(helpMenu);

		// Ajout de la barre dans la fenetre
		this.add(this.myMenuBar);
	}

	/**
	 * Création des panels
	 */
	public void initPanel() {
		// Récupération du nom des champs
		Ini.Section lang = langIni.get(VarLangInt.LANG_SECTION_BOUTON);

		// Mise en place des 3 panels
		splitPaneLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		splitPaneRight = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

		// Configuration des splitpanes
		splitPaneLeft
				.setDividerLocation((int) (screenSize.getWidth() * 0.5) - 30);
		// splitPaneRight.setDividerLocation((int)(screenSize.getHeight()*0.5)-13);

		// Ajout des panel dans les splitpane
		// Partie Haute
		splitPaneLeft.setLeftComponent(createImportPanel(lang));
		splitPaneLeft.setRightComponent(createMediaPanel(lang));

		this.refresh(splitPaneLeft.getLeftComponent());
		this.refresh(splitPaneLeft.getRightComponent());

		// Partie Basse
		splitPaneRight.setLeftComponent(splitPaneLeft);
		splitPaneRight.setRightComponent(createEditPanel(lang));

		this.refresh(splitPaneRight.getLeftComponent());
		this.refresh(splitPaneRight.getRightComponent());

		// Ajout au panel parent
		this.setLayout(new GridLayout(1, 0));
		this.add(splitPaneRight);
		this.refresh(this);
	}

	/**
	 * Creation du panel des imports video
	 * 
	 * @param lang
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "serial" })
	public JPanel createImportPanel(Ini.Section lang) {
		JPanel importPanel = new JPanel();

		listImport.setDragEnabled(true);
		//permet de drop d'une fenetre extern a la list
		listImport.setDropTarget(new DropTarget(){
            @SuppressWarnings("rawtypes")
			public synchronized void drop(DropTargetDropEvent dtde) {
            	System.out.println(dtde.toString());
                //super.drop(dtde);
            	dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                Transferable t = dtde.getTransferable();
                List fileList = null;
				try {
					fileList = (List)t.getTransferData(DataFlavor.javaFileListFlavor);
				} catch (UnsupportedFlavorException e) {
					new FenetreNewError(VarErreurInt.ERREUR_DRAG_FLAVOR_INVALIDE_TYPE);
				} catch (IOException e) {
					new FenetreNewError(VarErreurInt.ERREUR_DRAG_INVALIDE_TYPE);
				}
                File f = (File)fileList.get(0);
                myListImport.setLink(f.getAbsolutePath());
                myPlayer.setSrc(f.getAbsolutePath());
            }
        });
		listImport.setTransferHandler(new ListTransferHandler(this.myPlayer));
		listImport.setModel(listImportModel);
		
		importPanel.setLayout(new GridLayout(0,1));
		importPanel.add(new JScrollPane(listImport));

		return importPanel;
	}

	/**
	 * Creation du panel video
	 * 
	 * @param lang
	 * @return
	 */
	public JPanel createMediaPanel(Ini.Section lang) {
		// Ajout du canvas dans un panel
		canvasPanel = new JPanel();
		canvasPanel.add(this.canvas);

		// Ajout des boutons dans un autre panel
		JPanel boutonsPanel = new JPanel();
		boutonsPanel.setLayout(new FlowLayout());

		JButton playButton = new JButton(
				lang.get(VarLangInt.LANG_VAR_BOUTON_PLAY));
		JButton stopButton = new JButton(
				lang.get(VarLangInt.LANG_VAR_BOUTON_STOP));
		JButton nextFrameButton = new JButton(
				lang.get(VarLangInt.LANG_VAR_BOUTON_NEXT_FRAME));

		playButton.addActionListener(new ActionPlayerButtonListener(
				this.mediaPlayer, 0));
		stopButton.addActionListener(new ActionPlayerButtonListener(
				this.mediaPlayer, 1));
		nextFrameButton.addActionListener(new ActionPlayerButtonListener(
				this.mediaPlayer, 3));

		volumeSlider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent arg0) {
				mediaPlayer.setVolume(volumeSlider.getValue());
			}
		});

		boutonsPanel.add(playButton);
		boutonsPanel.add(stopButton);
		boutonsPanel.add(nextFrameButton);
		boutonsPanel.add(volumeSlider);
		
		// Panel regroupant les boutons et la vidéo
		JPanel lecteurPanel = new JPanel(new BorderLayout());
		lecteurPanel.add(canvasPanel, BorderLayout.CENTER);
		lecteurPanel.add(boutonsPanel, BorderLayout.SOUTH);
		JPanel test = new JPanel();
		test.add(lecteurPanel);
		
		//drag and drop sur panel de la video
		test.setTransferHandler(new ListTransferHandler(this.myPlayer));

		return test;
	}

	/**
	 * Création du panel de montage
	 * 
	 * @param lang
	 *            langue du fichier ini
	 * @return
	 */
	public JPanel createEditPanel(Ini.Section lang) {
		// parent panel
		editPanel = new JPanel(new BorderLayout());

		// cutting video panel
		JPanel cutPanel = new JPanel(new FlowLayout());
		// timebar panel
		JPanel timeBarPanel = new JPanel(new BorderLayout());
		
		this.setMediaProgressBar(this.mediaPlayer);

		// Evenement quand on appuie sur la barre
		this.timeBar.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				float pos = ((float) e.getX()) / timeBar.getWidth();
				mediaPlayer.setPosition(pos);
			}
		});
		
		//darg and drop d'une video sur timeBar
		timeBar.setTransferHandler(new ListTransferHandler(this.myPlayer));

		// Coupage
		startCutLabel = new JLabel("Debut :");
		endCutLabel = new JLabel("Durée :");

		// this.startTF = new JTextField(10);
		// this.durationTF = new JTextField(10);

		try {
			MaskFormatter startMaskF = new MaskFormatter("##:##:##");
			MaskFormatter durationMaskF = new MaskFormatter("##:##:##");
			this.startTF = new JFormattedTextField(startMaskF);
			this.durationTF = new JFormattedTextField(durationMaskF);
			this.startTF.setText(VarSystemInt.SYS_VIDEO_TIME);
			this.durationTF.setText(VarSystemInt.SYS_VIDEO_TIME);
		} catch (ParseException e1) {

		}

		cutButton = new JButton(lang.get(VarLangInt.LANG_VAR_BOUTON_CUT));
		cutButton.addActionListener(new ActionCutListener(this.myPlayer,
				this.startTF, this.durationTF, this.configIni));

		// concat multiples videos
		JButton chooseMultipleButton = new JButton(
				lang.get(VarLangInt.LANG_VAR_BOUTON_CONCAT));
		chooseMultipleButton.addActionListener(new ActionConcatVideoListener(this.configIni, this.fenetrePrincipale));

		cutPanel.add(chooseMultipleButton);
		cutPanel.add(startCutLabel);
		cutPanel.add(startTF);
		cutPanel.add(endCutLabel);
		cutPanel.add(durationTF);
		cutPanel.add(cutButton);

		// Timebar
		this.timeBar.setValue(0);
		this.timeBar.setPaintLabels(true);
		this.timeBar.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				JSlider source = (JSlider) e.getSource();
				float value = (float) (((float) source.getValue()) / 100);
				mediaPlayer.setPosition(value);
				currentTime.setText(getTimeVideo(mediaPlayer.getTime()));
				startTF.setText(getTimeVideo(mediaPlayer.getTime()));
			}
		});

		currentTime = new JLabel(VarSystemInt.SYS_VIDEO_TIME);
		endTime = new JLabel(VarSystemInt.SYS_VIDEO_TIME);

		timeBarPanel.add(currentTime, BorderLayout.WEST);
		timeBarPanel.add(this.timeBar, BorderLayout.CENTER);
		timeBarPanel.add(endTime, BorderLayout.EAST);

		editPanel.add(cutPanel, BorderLayout.NORTH);
		editPanel.add(timeBarPanel, BorderLayout.CENTER);
		return editPanel;
	}

	/**
	 * update the progress bar as the video progresses
	 */
	public void setMediaProgressBar(EmbeddedMediaPlayer mediaPlayer) {
		this.mediaPlayer
				.addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
					public void positionChanged(MediaPlayer mediaPlayer,
							float pos) {
						int value = Math.min(100, Math.round(pos * 100.0f));
						timeBar.setValue(value);
						currentTime.setText(getTimeVideo(mediaPlayer.getTime()));
						endTime.setText(getTimeVideo(mediaPlayer.getLength()));
					}
				});
	}

	/**
	 * Retourne le temps en hh:mm:ss de la valeur (en milliseconde passé en
	 * paramètre)
	 * 
	 * @param value
	 * @return
	 */
	public String getTimeVideo(long value) {
		int seconds = (int) (value / 1000) % 60;
		int minutes = (int) ((value / (1000 * 60)) % 60);
		int hours = (int) ((value / (1000 * 60 * 60)) % 24);
		return String.format("%02d:%02d:%02d", hours, minutes, seconds);
	}

	/**
	 * Se lance lors d'une mise a jour
	 * 
	 * @param o
	 * @param arg
	 */
	@SuppressWarnings("unchecked")
	public void update(Observable o, Object arg) {
		String param = (String) arg;
		if (o instanceof ModelMyPlayer) {
			this.volumeSlider.setValue(this.mediaPlayer.getVolume());
			this.mediaPlayer.playMedia(param); // Commence la video apres
		} else if (o instanceof ModelListImport) {
			boolean isContains = false;
			for (int i = 0; i < this.listImportModel.getSize(); i++) {
				if (this.listImportModel.getElementAt(i).toString()
						.equals(param)) {
					isContains = true;
					break;
				}
			}
			if (!isContains) {
				this.listImportModel.addElement(new ListItem(param));
				String pathTmp = param
						.substring(
								0,
								param.lastIndexOf(VarSystemInt.SYS_PROP_FILESEPARATOR) + 1);
				this.configIni.put(VarConfigInt.CONFIG_SECTION_PATH,
						VarConfigInt.CONFIG_VAR_PATH_MOVIES, pathTmp);
				try {
					this.configIni.store();
				} catch (IOException e) {
					new FenetreNewError(
							VarErreurInt.ERREUR_CONFIG_INVALIDE_TYPE);
				}
			}
			listImport.setModel(listImportModel);
		}
	}

	/**
	 * Se lance lorsque la fenetre se cache
	 */
	public void componentHidden(ComponentEvent arg0) {
	}

	/**
	 * Se lance lorsque l'on bouge la fenetre
	 */
	public void componentMoved(ComponentEvent arg0) {
	}

	/**
	 * Réorganise le lecteur vidéo afin qu'il soit responsive
	 */
	public void componentResized(ComponentEvent arg0) {
		this.canvas.setSize((int) (this.getWidth() * 0.5),
				(int) (this.getHeight() * 0.5));
	}

	/**
	 * S'execute lorsque la fenetre réapparait
	 */
	public void componentShown(ComponentEvent arg0) {
	}
}
